package storagetov2

import (
	"github.com/pkg/errors"
	"github.com/stackrox/rox/central/convert/helpers"
	v2 "github.com/stackrox/rox/generated/api/v2"
	"github.com/stackrox/rox/generated/storage"
	"github.com/stackrox/rox/pkg/utils"
)

func VirtualMachineVulnerabilities(vulnerabilities []*storage.VirtualMachineVulnerability) []*v2.EmbeddedVulnerability {
	return helpers.ConvertPointerArray(vulnerabilities, VirtualMachineVulnerability)
}

func VirtualMachineVulnerability(vulnerability *storage.VirtualMachineVulnerability) *v2.EmbeddedVulnerability {
	if vulnerability == nil {
		return nil
	}

	result := &v2.EmbeddedVulnerability{
		Cve:                   vulnerability.GetCveBaseInfo().GetCve(),
		Summary:               vulnerability.GetCveBaseInfo().GetSummary(),
		Link:                  vulnerability.GetCveBaseInfo().GetLink(),
		PublishedOn:           vulnerability.GetCveBaseInfo().GetPublishedOn(),
		LastModified:          vulnerability.GetCveBaseInfo().GetLastModified(),
		FirstSystemOccurrence: vulnerability.GetCveBaseInfo().GetCreatedAt(),
		CvssMetrics:           ScoreVersions(vulnerability.GetCveBaseInfo().GetCvssMetrics()),
		Epss:                  VirtualMachineEPSS(vulnerability.GetCveBaseInfo().GetEpss()),
		Cvss:                  vulnerability.GetCvss(),
		Severity:              convertVulnerabilitySeverity(vulnerability.GetSeverity()),
		Advisory:              VirtualMachineAdvisory(vulnerability.GetCveBaseInfo().GetAdvisory()),
	}

	if vulnerability.GetSetFixedBy() != nil {
		result.SetFixedBy = &v2.EmbeddedVulnerability_FixedBy{
			FixedBy: vulnerability.GetFixedBy(),
		}
	}

	return result
}

func convertVulnerabilityState(state storage.VulnerabilityState) v2.VulnerabilityState {
	switch state {
	case storage.VulnerabilityState_OBSERVED:
		return v2.VulnerabilityState_OBSERVED
	case storage.VulnerabilityState_DEFERRED:
		return v2.VulnerabilityState_DEFERRED
	case storage.VulnerabilityState_FALSE_POSITIVE:
		return v2.VulnerabilityState_FALSE_POSITIVE
	default:
		utils.Should(errors.Errorf("unhandled vulnerability state encountered %s", state))
		return v2.VulnerabilityState_OBSERVED
	}
}

func VirtualMachineAdvisory(advisory *storage.VirtualMachineAdvisory) *v2.Advisory {
	if advisory == nil {
		return nil
	}
	return &v2.Advisory{
		Name: advisory.GetName(),
		Link: advisory.GetLink(),
	}
}

func convertVulnerabilitySeverity(severity storage.VulnerabilitySeverity) v2.VulnerabilitySeverity {
	switch severity {
	case storage.VulnerabilitySeverity_UNKNOWN_VULNERABILITY_SEVERITY:
		return v2.VulnerabilitySeverity_UNKNOWN_VULNERABILITY_SEVERITY
	case storage.VulnerabilitySeverity_LOW_VULNERABILITY_SEVERITY:
		return v2.VulnerabilitySeverity_LOW_VULNERABILITY_SEVERITY
	case storage.VulnerabilitySeverity_MODERATE_VULNERABILITY_SEVERITY:
		return v2.VulnerabilitySeverity_MODERATE_VULNERABILITY_SEVERITY
	case storage.VulnerabilitySeverity_IMPORTANT_VULNERABILITY_SEVERITY:
		return v2.VulnerabilitySeverity_IMPORTANT_VULNERABILITY_SEVERITY
	case storage.VulnerabilitySeverity_CRITICAL_VULNERABILITY_SEVERITY:
		return v2.VulnerabilitySeverity_CRITICAL_VULNERABILITY_SEVERITY
	default:
		return v2.VulnerabilitySeverity_UNKNOWN_VULNERABILITY_SEVERITY
	}
}

func VirtualMachineEPSS(epss *storage.VirtualMachineEPSS) *v2.EPSS {
	if epss == nil {
		return nil
	}
	return &v2.EPSS{
		EpssProbability: epss.GetEpssProbability(),
		EpssPercentile:  epss.GetEpssPercentile(),
	}
}

func ScoreVersions(scores []*storage.CVSSScore) []*v2.CVSSScore {
	return helpers.ConvertPointerArray(scores, ScoreVersion)
}

func ScoreVersion(score *storage.CVSSScore) *v2.CVSSScore {
	if score == nil {
		return nil
	}
	return &v2.CVSSScore{
		Source: convertCVSSScoreSource(score.GetSource()),
		Url:    score.GetUrl(),
		Cvssv3: CvssV3(score.GetCvssv3()),
	}
}

func convertCVSSScoreSource(source storage.Source) v2.Source {
	switch source {
	case storage.Source_SOURCE_UNKNOWN:
		return v2.Source_SOURCE_UNKNOWN
	case storage.Source_SOURCE_RED_HAT:
		return v2.Source_SOURCE_RED_HAT
	case storage.Source_SOURCE_OSV:
		return v2.Source_SOURCE_OSV
	case storage.Source_SOURCE_NVD:
		return v2.Source_SOURCE_NVD
	default:
		return v2.Source_SOURCE_UNKNOWN
	}
}

func CvssV3(cvss *storage.CVSSV3) *v2.CVSSV3 {
	if cvss == nil {
		return nil
	}

	return &v2.CVSSV3{
		Vector:              cvss.GetVector(),
		ExploitabilityScore: cvss.GetExploitabilityScore(),
		ImpactScore:         cvss.GetImpactScore(),
		AttackVector:        convertAttackVectorV3(cvss.GetAttackVector()),
		AttackComplexity:    convertComplexity(cvss.GetAttackComplexity()),
		PrivilegesRequired:  convertPrivileges(cvss.GetPrivilegesRequired()),
		UserInteraction:     convertUserInteraction(cvss.GetUserInteraction()),
		Scope:               convertScope(cvss.GetScope()),
		Confidentiality:     convertImpactV3(cvss.GetConfidentiality()),
		Integrity:           convertImpactV3(cvss.GetIntegrity()),
		Availability:        convertImpactV3(cvss.GetAvailability()),
		Score:               cvss.GetScore(),
		Severity:            convertCVSSV3Severity(cvss.GetSeverity()),
	}
}

func convertCVSSV3Severity(severity storage.CVSSV3_Severity) v2.CVSSV3_Severity {
	return v2.CVSSV3_Severity(severity)
}

func convertAttackVectorV3(av storage.CVSSV3_AttackVector) v2.CVSSV3_AttackVector {
	return v2.CVSSV3_AttackVector(av)
}

func convertComplexity(ac storage.CVSSV3_Complexity) v2.CVSSV3_Complexity {
	return v2.CVSSV3_Complexity(ac)
}

func convertPrivileges(pr storage.CVSSV3_Privileges) v2.CVSSV3_Privileges {
	return v2.CVSSV3_Privileges(pr)
}

func convertUserInteraction(ui storage.CVSSV3_UserInteraction) v2.CVSSV3_UserInteraction {
	return v2.CVSSV3_UserInteraction(ui)
}

func convertScope(scope storage.CVSSV3_Scope) v2.CVSSV3_Scope {
	return v2.CVSSV3_Scope(scope)
}

func convertImpactV3(impact storage.CVSSV3_Impact) v2.CVSSV3_Impact {
	return v2.CVSSV3_Impact(impact)
}
